﻿using System;
using System.Collections.Generic;
using System.Reflection;
using System.Text.RegularExpressions;
using System.Web.UI;
using Cms.Utilities;

namespace Cms.Web.Framework
{
    public class ContentParser
    {
        public static void Parse(string html, Control container, string requestedUrl)
        {
            if (html.Length == 0)
                return;
            html = FixAnchors(html, requestedUrl);
            ParseContent(html, ref container);
        }
        
        private static string FixAnchors(string html, string requestedUrl)
        {
            // Check for links and replace all references to "#something" with 
            // absolute references to the current page followed by the anchor
            // The problem is that the base-tag causes all "#something" to end 
            // up at the default page instead of the current page.
            return Regex.Replace(html, "(<a[^>]+href=\")(\\#)([^\\\"]*)(\\\")", "$1" + requestedUrl + "#$3$4", RegexOptions.IgnoreCase);
        }

        private static void ParseContent(string content, ref Control container)
        {
            bool inPlugin = false;
            string[] allTokens = Regex.Split(content, "(<frediumplugin\\s)([^>]*)(>&nbsp;</frediumplugin>)", RegexOptions.Compiled | RegexOptions.IgnoreCase);
            foreach (string token in allTokens)
            {
                if (token == "<frediumplugin ")
                {
                    inPlugin = true;
                    continue;
                }
                if (inPlugin)
                {
                    if (token == ">&nbsp;</frediumplugin>")
                    {
                        inPlugin = false;
                        continue;
                    }
                    try
                    {
                        IDictionary<string, string> properties = new Dictionary<string, string>();
                        foreach (Match match in Regex.Matches(token, "([^\\s]+=\"[^\"]*\"|[^\\s]+)+"))
                        {
                            string name = match.Value.Substring(0, match.Value.IndexOf("="));
                            string value =
                                match.Value.Substring(match.Value.IndexOf("=") + 2).TrimEnd("\"".ToCharArray());
                            properties.Add(name, value);
                        }
                        Assembly a = Assembly.Load(properties["assemblyname"]);
                        Type pluginType = a.GetType(properties["classname"], true, true);
                        var plugin = (Control)Activator.CreateInstance(pluginType);
                        foreach (var kvp in properties)
                        {
                            if (kvp.Key == "pluginid" || kvp.Key == "assemblyname" || kvp.Key == "classname")
                                continue;
                            PropertyInfo pi = pluginType.GetProperty(kvp.Key, BindingFlags.Public | BindingFlags.Instance | BindingFlags.IgnoreCase);
                            string value = kvp.Value.Replace("%22", "\"")
                                .Replace("%3c", "<")
                                .Replace("%3e", ">")
                                .Replace("%27", "'")
                                .Replace("%5c", "\\")
                                .Replace("%25", "%");
                            if (pi.PropertyType.BaseType == typeof(Enum))
                            {
                                pi.SetValue(plugin, Enum.Parse(pi.PropertyType, value, true), null);
                            }
                            else
                                pi.SetValue(plugin, Convert.ChangeType(value, pi.PropertyType), null);
                        }
                        container.Controls.Add(plugin);
                    }
                    catch (Exception ex)
                    {
                        Logging.LogError(string.Empty, ex);
                    }
                }
                else
                {
                    container.Controls.Add(new LiteralControl(token));
                }
            }
        }
    }
}